home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / prg_casm / snip9611.zip / DEQUEUE.C < prev    next >
C/C++ Source or Header  |  1996-11-24  |  18KB  |  840 lines

  1. /* +++Date last modified: 02-Nov-1995 */
  2.  
  3.  
  4. /****************************************************************
  5.  *
  6.  *  File : QUEUE.c
  7.  *
  8.  *  Author: Peter Yard [1993.01.02] -- 02 Jan 1993
  9.  *
  10.  *  Disclaimer: This code is released to the public domain.
  11.  *
  12.  *  Description:
  13.  *      Generic double ended queue (Deque pronounced DEK) for handling
  14.  *      any data types, with sorting.
  15.  *
  16.  *      By use of various functions in this module the caller
  17.  *      can create stacks, queues, lists, doubly linked lists,
  18.  *      sorted lists, indexed lists.  All lists are dynamic.
  19.  *
  20.  *      It is the responsibility of the caller to malloc and free
  21.  *      memory for insertion into the queue. A pointer to the object
  22.  *      is used so that not only can any data be used but various kinds
  23.  *      of data can be pushed on the same queue if one so wished e.g.
  24.  *      various length string literals mixed with pointers to structures
  25.  *      or integers etc.
  26.  *
  27.  *  Enhancements:
  28.  *      A future improvement would be the option of multiple "cursors"
  29.  *      so that multiple locations could occur in the one queue to allow
  30.  *      placemarkers and additional flexibility.  Perhaps even use queue
  31.  *      itself to have a list of cursors.
  32.  *
  33.  * Usage:
  34.  *
  35.  *          /x init queue x/
  36.  *          queue  q;
  37.  *          Q_Init( &q );
  38.  *
  39.  *      To create a stack :
  40.  *
  41.  *          Q_PushHead( &q, &mydata1 ); /x push x/
  42.  *          Q_PushHead( &q, &mydata2 );
  43.  *          .....
  44.  *          data_ptr = Q_PopHead( &q ); /x pop x/
  45.  *          .....
  46.  *          data_ptr = Q_First( &q );   /x top of stack x/
  47.  *
  48.  *      To create a FIFO:
  49.  *
  50.  *          Q_PushHead( &q, &mydata1 );
  51.  *          .....
  52.  *          data_ptr = Q_PopTail( &q );
  53.  *
  54.  *      To create a double list:
  55.  *
  56.  *          data_ptr = Q_First( &q );
  57.  *          ....
  58.  *          data_ptr = Q_Next( &q );
  59.  *          data_ptr = Q_Last( &q );
  60.  *          if ( Q_Empty(&q) ) ....
  61.  *          .....
  62.  *          data_ptr = Q_Previous( &q );
  63.  *
  64.  *      To create a sorted list:
  65.  *
  66.  *          Q_PushHead( &q, &mydata1 ); /x push x/
  67.  *          Q_PushHead( &q, &mydata2 );
  68.  *          .....
  69.  *          if (!Q_Sort( &q, MyFunction ))
  70.  *              .. error ..
  71.  *
  72.  *          /x fill in key field of mydata1.
  73.  *           * NB: Q_Find does linear search
  74.  *           x/
  75.  *
  76.  *          if ( Q_Find( &q, &mydata1, MyFunction ) )
  77.  *          {
  78.  *              /x found it, queue cursor now at correct record x/
  79.  *              /x can retrieve with x/
  80.  *              data_ptr = Q_Get( &q );
  81.  *
  82.  *              /x alter data , write back with x/
  83.  *              Q_Put( &q, data_ptr );
  84.  *          }
  85.  *
  86.  *          /x Search with binary search x/
  87.  *          if ( Q_Seek( &q, &mydata, MyFunction ) )
  88.  *              /x etc x/
  89.  *
  90.  *
  91.  ****************************************************************/
  92.  
  93.  
  94. #include <stdlib.h>
  95.  
  96. #include "dequeue.h"
  97.  
  98. /* The index: a pointer to pointers */
  99. static  void        **index;
  100. static  datanode    **posn_index;
  101.  
  102. /***
  103.  *
  104.  ** function    : Q_Init
  105.  *
  106.  ** purpose     : Initialise queue object and pointers.
  107.  *
  108.  ** parameters  : 'queue' pointer.
  109.  *
  110.  ** returns     : True_ if init successful else False_
  111.  *
  112.  ** comments    :
  113.  ***/
  114. int  Q_Init( queue  *q ) {
  115.  
  116.     q->head = q->tail = NULL;
  117.     q->cursor = q->head ;
  118.     q->size = 0;
  119.     q->sorted = False_;
  120.  
  121.     return True_;
  122. }
  123.  
  124. /***
  125.  *
  126.  ** function    : Q_Start
  127.  *
  128.  ** purpose     : tests if cursor is at head of queue
  129.  *
  130.  ** parameters  : 'queue' pointer.
  131.  *
  132.  ** returns     : boolean - True_ is at head else False_
  133.  *
  134.  ** comments    :
  135.  *
  136.  ***/
  137. int  Q_Start( queue *q ) {
  138.  
  139.     return ( q->cursor == q->head );
  140. }
  141.  
  142.  
  143. /***
  144.  *
  145.  ** function    : Q_End
  146.  *
  147.  ** purpose     : boolean test if cursor at tail of queue
  148.  *
  149.  ** parameters  : 'queue' pointer to test.
  150.  *
  151.  ** returns     : True_ or False_
  152.  *
  153.  ** comments    :
  154.  *
  155.  ***/
  156. int  Q_End( queue *q ) {
  157.  
  158.     return ( q->cursor == q->tail );
  159. }
  160.  
  161.  
  162. /***
  163.  *
  164.  ** function    : Q_Empty
  165.  *
  166.  ** purpose     : test if queue has nothing in it.
  167.  *
  168.  ** parameters  : 'queue' pointer
  169.  *
  170.  ** returns     : True_ if empty queue, else False_
  171.  *
  172.  ** comments    :
  173.  *
  174.  ***/
  175. int  Q_Empty( queue *q ){
  176.  
  177.     return (q->size == 0);
  178. }
  179.  
  180. /***
  181.  *
  182.  ** function    : Q_Size
  183.  *
  184.  ** purpose     : return the number of elements in the queue
  185.  *
  186.  ** parameters  : queue pointer
  187.  *
  188.  ** returns     : number of elements
  189.  *
  190.  ** comments    :
  191.  *
  192.  ***/
  193. int  Q_Size( queue *q ) {
  194.  
  195.     return q->size ;
  196. }
  197.  
  198.  
  199. /***
  200.  *
  201.  ** function    : Q_First
  202.  *
  203.  ** purpose     : position queue cursor to first element (head) of queue.
  204.  *
  205.  ** parameters  : 'queue' pointer
  206.  *
  207.  ** returns     : pointer to data at head. If queue is empty returns NULL
  208.  *
  209.  ** comments    :
  210.  *
  211.  ***/
  212. void *Q_First( queue *q ) {
  213.  
  214.     if ( Q_Empty(q) )
  215.         return NULL;
  216.  
  217.     q->cursor = q->head;
  218.  
  219.     return  q->cursor->data ;
  220. }
  221.  
  222.  
  223. /***
  224.  *
  225.  ** function    : Q_Last
  226.  *
  227.  ** purpose     : locate cursor at tail of queue.
  228.  *
  229.  ** parameters  : 'queue' pointer
  230.  *
  231.  ** returns     : pointer to data at tail , if queue empty returns NULL
  232.  *
  233.  ** comments    :
  234.  *
  235.  ***/
  236. void *Q_Last( queue *q ) {
  237.  
  238.     if ( Q_Empty(q) )
  239.         return NULL;
  240.  
  241.     q->cursor = q->tail;
  242.  
  243.     return  q->cursor->data ;
  244.  
  245. }
  246.  
  247.  
  248. /***
  249.  *
  250.  ** function    : Q_PushHead
  251.  *
  252.  ** purpose     : put a data pointer at the head of the queue
  253.  *
  254.  ** parameters  : 'queue' pointer, void pointer to the data.
  255.  *
  256.  ** returns     : True_ if success else False_ if unable to push data.
  257.  *
  258.  ** comments    :
  259.  *
  260.  ***/
  261. int  Q_PushHead( queue *q, void *d ) {
  262.  
  263.     node    *n ;
  264.     datanode *p;
  265.  
  266.     q->head->prev = malloc( sizeof(datanode) );
  267.     if ( q->head->prev == NULL )
  268.         return False_;
  269.  
  270.     n = q->head;
  271.  
  272.     p = q->head->prev;
  273.     q->head = (node*)p ;
  274.     q->head->prev = NULL;
  275.  
  276.     if ( q->size == 0 ) {
  277.         q->head->next = NULL ;
  278.         q->tail = q->head;
  279.     } else
  280.         q->head->next = (datanode*)n;
  281.  
  282.     q->head->data = d ;
  283.     q->size++;
  284.  
  285.     q->cursor = q->head;
  286.  
  287.     q->sorted = False_;
  288.  
  289.     return True_;
  290. }
  291.  
  292.  
  293.  
  294. /***
  295.  *
  296.  ** function    : Q_PushTail
  297.  *
  298.  ** purpose     : put a data element pointer at the tail of the queue
  299.  *
  300.  ** parameters  : queue pointer, pointer to the data
  301.  *
  302.  ** returns     : True_ if data pushed, False_ if data not inserted.
  303.  *
  304.  ** comments    :
  305.  *
  306.  ***/
  307. int  Q_PushTail( queue *q, void *d ) {
  308.  
  309.     node        *p;
  310.     datanode    *n;
  311.  
  312.     q->tail->next = malloc( sizeof(datanode) );
  313.     if ( q->tail->next == NULL )
  314.         return False_;
  315.  
  316.     p = q->tail;
  317.     n = q->tail->next;
  318.     q->tail = (node *)n ;
  319.  
  320.     if ( q->size == 0 ) {
  321.         q->tail->prev = NULL ;
  322.         q->head = q->tail;
  323.     } else
  324.         q->tail->prev = (datanode *)p;
  325.  
  326.     q->tail->next = NULL;
  327.  
  328.     q->tail->data =  d ;
  329.     q->cursor = q->tail;
  330.     q->size++;
  331.  
  332.     q->sorted = False_;
  333.  
  334.     return True_;
  335. }
  336.  
  337.  
  338.  
  339. /***
  340.  *
  341.  ** function    : Q_PopHead
  342.  *
  343.  ** purpose     : remove and return the top element at the head of the
  344.  *                queue.
  345.  *
  346.  ** parameters  : queue pointer
  347.  *
  348.  ** returns     : pointer to data element or NULL if queue is empty.
  349.  *
  350.  ** comments    :
  351.  *
  352.  ***/
  353. void *Q_PopHead( queue *q ) {
  354.  
  355.     datanode    *n;
  356.     void        *d;
  357.  
  358.     if ( Q_Empty(q) ) return NULL;
  359.  
  360.     d = q->head->data ;
  361.     n = q->head->next;
  362.     free( q->head );
  363.  
  364.     q->size--;
  365.  
  366.     if ( q->size == 0 )
  367.         q->head = q->tail = q->cursor = NULL;
  368.     else {
  369.         q->head = (node *)n;
  370.         q->head->prev = NULL;
  371.         q->cursor = q->head;
  372.     }
  373.  
  374.     q->sorted = False_;
  375.  
  376.     return d;
  377. }
  378.  
  379.  
  380. /***
  381.  *
  382.  ** function    : Q_PopTail
  383.  *
  384.  ** purpose     : remove element from tail of queue and return data.
  385.  *
  386.  ** parameters  : queue pointer
  387.  *
  388.  ** returns     : pointer to data element that was at tail. NULL if queue
  389.  *                empty.
  390.  *
  391.  ** comments    :
  392.  *
  393.  ***/
  394. void *Q_PopTail( queue *q ) {
  395.  
  396.     datanode    *p;
  397.     void        *d;
  398.  
  399.     if ( Q_Empty(q) ) return NULL;
  400.  
  401.     d = q->tail->data ;
  402.     p = q->tail->prev;
  403.     free( q->tail );
  404.     q->size--;
  405.  
  406.     if ( q->size == 0 )
  407.         q->head = q->tail = q->cursor = NULL;
  408.     else {
  409.         q->tail = (node * )p;
  410.         q->tail->next = NULL;
  411.         q->cursor = q->tail;
  412.     }
  413.  
  414.     q->sorted = False_;
  415.  
  416.     return d;
  417. }
  418.  
  419.  
  420.  
  421. /***
  422.  *
  423.  ** function    : Q_Next
  424.  *
  425.  ** purpose     : Move to the next element in the queue without popping
  426.  *
  427.  ** parameters  : queue pointer.
  428.  *
  429.  ** returns     : pointer to data element of new element or NULL if end
  430.  *                of the queue.
  431.  *
  432.  ** comments    : This uses the cursor for the current position. Q_Next
  433.  *                only moves in the direction from the head of the queue
  434.  *                to the tail.
  435.  ***/
  436. void *Q_Next( queue *q ) {
  437.  
  438.     if (q->cursor->next == NULL)
  439.         return NULL;
  440.  
  441.     q->cursor = (node *)q->cursor->next ;
  442.  
  443.     return  q->cursor->data  ;
  444.  
  445. }
  446.  
  447.  
  448.  
  449. /***
  450.  *
  451.  ** function    : Q_Previous
  452.  *
  453.  ** purpose     : Opposite of Q_Next. Move to next element closer to the
  454.  *                head of the queue.
  455.  *
  456.  ** parameters  : pointer to queue
  457.  *
  458.  ** returns     : pointer to data of new element else NULL if queue empty
  459.  *
  460.  ** comments    : Makes cursor move towards the head of the queue.
  461.  *
  462.  ***/
  463. void *Q_Previous( queue *q ) {
  464.  
  465.     if (q->cursor->prev == NULL)
  466.         return NULL;
  467.  
  468.     q->cursor = (node *)q->cursor->prev ;
  469.  
  470.     return q->cursor->data ;
  471.  
  472. }
  473.  
  474.  
  475.  
  476. /***
  477.  *
  478.  ** function    : Q_DelCur
  479.  *
  480.  ** purpose     : Delete the current queue element as pointed to by
  481.  *                the cursor.
  482.  *
  483.  ** parameters  : queue pointer
  484.  *
  485.  ** returns     : pointer to data element.
  486.  *
  487.  ** comments    : WARNING! It is the responsibility of the caller to
  488.  *                free any memory. Queue cannot distinguish between
  489.  *                pointers to literals and malloced memory.
  490.  *
  491.  ***/
  492. void    *Q_DelCur( queue *q ) {
  493.  
  494.     void    *d;
  495.     datanode    *n, *p ;
  496.  
  497.     if ( q->cursor == NULL )
  498.         return NULL;
  499.  
  500.     if (q->cursor == q->head)
  501.         return Q_PopHead( q ) ;
  502.  
  503.     if (q->cursor == q->tail)
  504.         return Q_PopTail( q );
  505.  
  506.     n = q->cursor->next;
  507.     p = q->cursor->prev;
  508.     d = q->cursor->data;
  509.  
  510.     free( q->cursor );
  511.     if ( p != NULL )
  512.         q->cursor = p ;
  513.     else
  514.         q->cursor = n ;
  515.     q->size--;
  516.  
  517.     q->sorted = False_;
  518.  
  519.     return d;
  520. }
  521.  
  522.  
  523.  
  524. /***
  525.  *
  526.  ** function    : Q_Get
  527.  *
  528.  ** purpose     : get the pointer to the data at the cursor location
  529.  *
  530.  ** parameters  : queue pointer
  531.  *
  532.  ** returns     : data element pointer
  533.  *
  534.  ** comments    :
  535.  *
  536.  ***/
  537. void    *Q_Get( queue *q ) {
  538.  
  539.     if ( q->cursor == NULL )
  540.         return NULL ;
  541.     return q->cursor->data ;
  542. }
  543.  
  544.  
  545.  
  546. /***
  547.  *
  548.  ** function    : Q_Put
  549.  *
  550.  ** purpose     : replace pointer to data with new pointer to data.
  551.  *
  552.  ** parameters  : queue pointer, data pointer
  553.  *
  554.  ** returns     : boolean- True_ if successful, False_ if cursor at NULL
  555.  *
  556.  ** comments    :
  557.  *
  558.  ***/
  559. int     Q_Put( queue *q, void *data ) {
  560.  
  561.     if ( q->cursor == NULL )
  562.         return False_ ;
  563.  
  564.     q->cursor->data = data ;
  565.     return True_;
  566. }
  567.  
  568.  
  569. /***
  570.  *
  571.  ** function    : Q_Find
  572.  *
  573.  ** purpose     : Linear search of queue for match with key in *data
  574.  *
  575.  ** parameters  : queue pointer q, data pointer with data containing key
  576.  *                comparison function here called Comp.
  577.  *
  578.  ** returns     : True_ if found , False_ if not in queue.
  579.  *
  580.  ** comments    : Useful for small queues that are constantly changing
  581.  *                and would otherwise need constant sorting with the
  582.  *                Q_Seek function.
  583.  *                For description of Comp see Q_Sort.
  584.  *                Queue cursor left on position found item else at end.
  585.  *
  586.  ***/
  587. int     Q_Find( queue *q, void *data,
  588.             int Comp(const void *, const void *) ) {
  589.  
  590.     void  *d;
  591.     d = Q_First( q );
  592.     do {
  593.  
  594.         if ( Comp( d, data ) == 0 )
  595.             return True_;
  596.         d = Q_Next( q );
  597.  
  598.     } while ( !Q_End(q) );
  599.  
  600.     if ( Comp( d, data ) == 0 )
  601.         return True_;
  602.  
  603.     return False_;
  604. }
  605.  
  606. /*========  Sorted Queue and Index functions   ========= */
  607.  
  608.  
  609. static void QuickSort( void *list[], int low, int high,
  610.                         int Comp( const void *, const void * ) ) {
  611.  
  612.     int     flag = 1, i, j ;
  613.     void    *key, *temp ;
  614.  
  615.     if ( low < high ) {
  616.  
  617.         i = low;
  618.         j = high + 1;
  619.  
  620.         key = list[ low ];
  621.  
  622.         while ( flag ) {
  623.  
  624.             i++;
  625.             while ( Comp( list[i], key ) < 0 )
  626.                 i++;
  627.  
  628.             j--;
  629.             while ( Comp( list[j], key ) > 0 )
  630.                 j--;
  631.  
  632.             if ( i < j ) {
  633.  
  634.                 temp = list[i];
  635.                 list[i] = list[j];
  636.                 list[j] = temp ;
  637.  
  638.             } else
  639.                 flag = 0;
  640.         }
  641.  
  642.         temp = list[low];
  643.         list[low] = list[j];
  644.         list[j] = temp ;
  645.  
  646.         QuickSort( list, low, j-1, Comp );
  647.         QuickSort( list, j+1, high, Comp );
  648.     }
  649. }
  650.  
  651.  
  652. /***
  653.  *
  654.  ** function    : Q_Sort
  655.  *
  656.  ** purpose     : sort the queue and allow index style access.
  657.  *
  658.  ** parameters  : queue pointer, comparison function compatible with
  659.  *                with 'qsort'.
  660.  *
  661.  ** returns     : True_ if sort succeeded. False_ if error occurred.
  662.  *
  663.  ** comments    : Comp function supplied by caller must return
  664.  *                  -1 if data1  < data2
  665.  *                   0 if data1 == data2
  666.  *                  +1 if data1  > data2
  667.  *
  668.  *                    for Comp( data1, data2 )
  669.  *
  670.  *                If queue is already sorted it frees the memory of the
  671.  *                old index and starts again.
  672.  *
  673.  ***/
  674. int     Q_Sort( queue *q, int Comp(const void *, const void *) ) {
  675.  
  676.     int         i ;
  677.     void        *d;
  678.     datanode    *dn;
  679.  
  680.     /* if already sorted free memory for tag array */
  681.     if ( q->sorted ) {
  682.         free( index );
  683.         free( posn_index );
  684.         q->sorted = False_;
  685.     }
  686.  
  687.     /* Now allocate memory of array, array of pointers */
  688.     index = malloc( q->size * sizeof( q->cursor->data ) );
  689.     if ( index == NULL )
  690.         return False_;
  691.  
  692.     posn_index = malloc( q->size * sizeof( q->cursor ) );
  693.     if ( posn_index == NULL ) {
  694.         free( index);
  695.         return False_;
  696.     }
  697.  
  698.     /* Walk queue putting pointers into array */
  699.     d = Q_First( q );
  700.     for ( i=0; i < q->size; i++) {
  701.  
  702.         index[i] = d;
  703.         posn_index[i] = q->cursor ;
  704.         d = Q_Next( q );
  705.     }
  706.  
  707.     /* Now sort the index */
  708.     QuickSort( index, 0, q->size - 1, Comp );
  709.  
  710.     /* Rearrange the actual queue into correct order */
  711.     dn = q->head;
  712.     i = 0;
  713.     while ( dn != NULL ) {
  714.         dn->data = index[i++];
  715.         dn = dn->next ;
  716.     }
  717.  
  718.     /* Re-position to original element */
  719.     if ( d != NULL )
  720.         Q_Find( q, d, Comp );
  721.     else
  722.         Q_First( q );
  723.  
  724.     q->sorted = True_;
  725.  
  726.     return True_;
  727. }
  728.  
  729.  
  730. /***
  731.  *
  732.  ** function    : Q_BSearch
  733.  *
  734.  ** purpose     : binary search of queue index for node containing key
  735.  *
  736.  ** parameters  : queue pointer 'q', data pointer of key 'key',
  737.  *                  Comp comparison function.
  738.  *
  739.  ** returns     : integer index into array of node pointers,
  740.  *                or -1 if not found.
  741.  *
  742.  ** comments    : see Q_Sort for description of 'Comp' function.
  743.  *
  744.  ***/
  745.  static  int    Q_BSearch(  queue *q, void *key,
  746.                             int Comp(const void *, const void*) ) {
  747.     int     low, mid, hi, val;
  748.  
  749.     low = 0;
  750.     hi = q->size - 1;
  751.  
  752.     while ( low <= hi ) {
  753.  
  754.         mid = (low + hi ) / 2;
  755.         val = Comp( key, index[ mid ] ) ;
  756.  
  757.         if ( val < 0 )
  758.  
  759.             hi = mid - 1;
  760.  
  761.         else if ( val > 0 )
  762.  
  763.             low = mid + 1;
  764.  
  765.         else /* Success */
  766.  
  767.             return mid;
  768.  
  769.     }
  770.  
  771.     /* Not Found */
  772.     return -1;
  773.  }
  774.  
  775.  
  776. /***
  777.  *
  778.  ** function    : Q_Seek
  779.  *
  780.  ** purpose     : use index to locate data according to key in 'data'
  781.  *
  782.  ** parameters  : queue pointer 'q', data pointer 'data', Comp comparison
  783.  *                function.
  784.  *
  785.  ** returns     : pointer to data or NULL if could not find it or could
  786.  *                not sort queue.
  787.  *
  788.  ** comments    : see Q_Sort for description of 'Comp' function.
  789.  *
  790.  ***/
  791. void    *Q_Seek( queue *q, void *data, int Comp(const void *,
  792.                     const void *) ) {
  793.  
  794.     int     idx;
  795.  
  796.     if ( !q->sorted )
  797.         if ( !Q_Sort( q, Comp ) )
  798.             return NULL ;
  799.  
  800.     idx = Q_BSearch( q, data, Comp );
  801.  
  802.     if ( idx < 0 )
  803.         return NULL;
  804.  
  805.     q->cursor = posn_index[idx] ;
  806.  
  807.     return index[idx];
  808. }
  809.  
  810.  
  811.  
  812. /***
  813.  *
  814.  ** function    : Q_Insert
  815.  *
  816.  ** purpose     : Insert an element into an indexed queue
  817.  *
  818.  ** parameters  : queue pointer 'q', data pointer 'data', Comp comparison
  819.  *                function.
  820.  *
  821.  ** returns     : pointer to data or NULL if could not find it or could
  822.  *                not sort queue.
  823.  *
  824.  ** comments    : see Q_Sort for description of 'Comp' function.
  825.  *                WARNING! This code can be very slow since each new
  826.  *                element means a new Q_Sort.  Should only be used for
  827.  *                the insertion of the odd element ,not the piecemeal
  828.  *                building of an entire queue.
  829.  ***/
  830. int     Q_Insert( queue *q, void *data, int Comp(const void *,
  831.                     const void *) ) {
  832.  
  833.     Q_PushHead( q, data );
  834.  
  835.     if ( !Q_Sort( q, Comp ) )
  836.         return False_ ;
  837.  
  838.     return True_;
  839. }
  840.